home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / arp.c next >
C/C++ Source or Header  |  1994-06-04  |  12KB  |  397 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  4.  *
  5.  * Mods by G1EMM
  6.  *
  7.  * Mods by SM6RPZ
  8.  * 1992-05-28 - Added interface to arp_lookup() and arp_add().
  9.  * 1992-07-07 - Added arp_timeout(). This function now works according to the
  10.  *              last page in RFC826. When an ARP entry times out we will first
  11.  *              try an ARP reply before deleting the entry.
  12.  * 1992-07-08 - We will update the ARP table and create new entries each time
  13.  *              we hear an ARP request message on the channel. By doing so we
  14.  *              will gain knowledge of other stations hardware addresses
  15.  *              whithout sending a lot of ARP requests. If we are running RSPF,
  16.  *              it will be informed about these "findings".
  17.  * 1992-07-11 - Datagrams to be sent while awaiting an resolution will be put
  18.  *              on a queue. The length of this queue in datagrams is defined
  19.  *              in arp.h (ARP_QUEUE).
  20.  *
  21.  * 1992-10-27 The above 3 behaviours are now configurable via additional
  22.  *      arp subcommands - WG7J
  23.  *
  24.  */
  25.  
  26. #include "global.h"
  27. #include "config.h"
  28. #include "mbuf.h"
  29. #include "timer.h"
  30. #include "iface.h"
  31. #ifdef ETHER
  32. #include "enet.h"
  33. #endif
  34. #include "ax25.h"
  35. #include "icmp.h"
  36. #include "ip.h"
  37. #include "arp.h"
  38. #include "icmp.h"
  39. #include "rspf.h"
  40.  
  41. extern int Maxarpq;
  42.  
  43. static void arp_output __ARGS((struct iface *iface,int16 hardware,int32 target,char *hw_addr));
  44. static void arp_timeout __ARGS((void *p));  /* sm6rpz */
  45.  
  46. /* Hash table headers */
  47. struct arp_tab *Arp_tab[HASHMOD];
  48. struct arp_stat Arp_stat;
  49.  
  50. /* Resolve an IP address to a hardware address; if not found,
  51.  * initiate query and return NULLCHAR.  If an address is returned, the
  52.  * interface driver may send the packet; if NULLCHAR is returned,
  53.  * res_arp() will have saved the packet on its pending queue,
  54.  * so no further action (like freeing the packet) is necessary.
  55.  */
  56. char *
  57. res_arp(iface,hardware,target,bp)
  58. struct iface *iface;    /* Pointer to interface block */
  59. int16 hardware;         /* Hardware type */
  60. int32 target;           /* Target IP address */
  61. struct mbuf *bp;        /* IP datagram to be queued if unresolved */
  62. {
  63.     register struct arp_tab *arp;
  64.     struct ip ip;
  65.  
  66.     if((arp = arp_lookup(hardware,target,iface)) != NULLARP && arp->state == ARP_VALID)
  67.         return arp->hw_addr;
  68.     if(arp != NULLARP){
  69.     if(len_q(arp->pending) > Maxarpq) {
  70.             /* Earlier packets are already pending, kick
  71.              * this one back as a source quench
  72.              */
  73.             ntohip(&ip,&bp);
  74.             icmp_output(&ip,bp,ICMP_QUENCH,0,NULL);
  75.             free_p(bp);
  76.         } else
  77.         enqueue(&arp->pending,bp);
  78.     } else {
  79.         /* Create an entry and put the datagram on the
  80.          * queue pending an answer
  81.          */
  82.     arp = arp_add(target,hardware,NULLCHAR,0,iface);
  83.         enqueue(&arp->pending,bp);
  84.     arp_output(iface,hardware,target,NULLCHAR);
  85.     }
  86.     return NULLCHAR;
  87. }
  88.  
  89. /* Handle incoming ARP packets. This is almost a direct implementation of
  90.  * the algorithm on page 5 of RFC 826, except for:
  91.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  92.  *    pending a reply to our ARP request.
  93.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  94.  * 3. Requests for IP addresses listed in our table as "published" are
  95.  *    responded to, even if the address is not our own.
  96.  */
  97. void
  98. arp_input(iface,bp)
  99. struct iface *iface;
  100. struct mbuf *bp;
  101. {
  102.     struct arp arp;
  103.     struct arp_tab *ap;
  104.     struct arp_type *at;
  105.     int i;
  106.     
  107.     Arp_stat.recv++;
  108.     if(ntoharp(&arp,&bp) == -1)     /* Convert into host format */
  109.         return;
  110.     if(arp.hardware >= NHWTYPES){
  111.         /* Unknown hardware type, ignore */
  112.         Arp_stat.badtype++;
  113.         return;
  114.     }
  115.     at = &Arp_type[arp.hardware];
  116.     if(arp.protocol != at->iptype){
  117.         /* Unsupported protocol type, ignore */
  118.         Arp_stat.badtype++;
  119.         return;
  120.     }
  121.     if((int16)uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  122.         /* Incorrect protocol addr length (different hw addr lengths
  123.          * are OK since AX.25 addresses can be of variable length)
  124.          */
  125.         Arp_stat.badlen++;
  126.         return;
  127.       
  128.     }
  129.     if(arp.sprotaddr == 0L || arp.tprotaddr == 0L){
  130.         /* We are going to dead-end references for [0.0.0.0], since
  131.          * experience shows that these cause total lock up -- N1BEE
  132.          */
  133.         Arp_stat.badaddr++;
  134.         return;
  135.     }
  136.     if(memcmp(arp.shwaddr,at->bdcst,(size_t)at->hwalen) == 0){
  137.         /* This guy is trying to say he's got the broadcast address! */
  138.         Arp_stat.badaddr++;
  139.         return;
  140.     }
  141.     /* Try to refine ARP according to section 5.7 in Douglas E.
  142.      * Comers book "Internetworking With TCP/IP", 2nd ed. page 77.
  143.      * I.e we will use all ARP-packets we can see thereby lessen
  144.      * the ARP traffic a little. -- sm6rpz
  145.      */
  146.     if(((ap = arp_lookup(arp.hardware,arp.sprotaddr,iface)) != NULLARP
  147.     && dur_timer(&ap->timer) != 0)
  148.        || ( (iface->flags & ARP_EAVESDROP) &&
  149.         ap == NULLARP && arp.opcode != REVARP_REQUEST)
  150.       ) {
  151.     ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0,iface);
  152.     }
  153.     /* See if we're the address they're looking for */
  154.     if(ismyaddr(arp.tprotaddr) != NULLIF){
  155.     if(ap == NULLARP)   /* Only if not already in the table */
  156.         arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0,iface);
  157.  
  158.         if(arp.opcode == ARP_REQUEST){
  159.         /* Swap sender's and target's (us) hardware and protocol
  160.              * fields, and send the packet back as a reply
  161.              */
  162.             memcpy(arp.thwaddr,arp.shwaddr,(size_t)uchar(arp.hwalen));
  163.             /* Mark the end of the sender's AX.25 address
  164.              * in case he didn't
  165.              */
  166.             if(arp.hardware == ARP_AX25)
  167.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  168.  
  169.             memcpy(arp.shwaddr,iface->hwaddr,(size_t)at->hwalen);
  170.             arp.tprotaddr = arp.sprotaddr;
  171.             arp.sprotaddr = iface->addr;
  172.             arp.opcode = ARP_REPLY;
  173.             if((bp = htonarp(&arp)) == NULLBUF)
  174.                 return;
  175.  
  176.             if(iface->forw != NULLIF)
  177.                 (*iface->forw->output)(iface->forw,
  178.                  arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  179.             else 
  180.                 (*iface->output)(iface,arp.thwaddr,
  181.                  iface->hwaddr,at->arptype,bp);
  182.             Arp_stat.inreq++;
  183. #ifdef  RSPF
  184.             /* Do an RSPF upcall */
  185.             rspfarpupcall(arp.tprotaddr,arp.hardware,NULLIF);
  186. #endif  /* RSPF*/
  187.         } else {
  188.             Arp_stat.replies++;
  189. #ifdef  RSPF
  190.             /* Do an RSPF upcall */
  191.             rspfarpupcall(arp.sprotaddr,arp.hardware,iface);
  192. #endif  /* RSPF*/
  193.         }
  194.     } else if(arp.opcode == ARP_REQUEST
  195.      && (ap = arp_lookup(arp.hardware,arp.tprotaddr,iface)) != NULLARP
  196.      && ap->pub){
  197.         /* Otherwise, respond if the guy he's looking for is
  198.          * published in our table.
  199.          */
  200.         memcpy(arp.thwaddr,arp.shwaddr,(size_t)uchar(arp.hwalen));
  201.         memcpy(arp.shwaddr,ap->hw_addr,(size_t)at->hwalen);
  202.         arp.tprotaddr = arp.sprotaddr;
  203.         arp.sprotaddr = ap->ip_addr;
  204.         arp.opcode = ARP_REPLY;
  205.         if((bp = htonarp(&arp)) == NULLBUF)
  206.             return;
  207.         if(iface->forw != NULLIF)
  208.             (*iface->forw->output)(iface->forw,
  209.              arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  210.         else 
  211.             (*iface->output)(iface,arp.thwaddr,
  212.              iface->hwaddr,at->arptype,bp);
  213.         Arp_stat.inreq++;
  214.     } else if(arp.opcode == REVARP_REQUEST){
  215.         for(i=0;i<HASHMOD;i++)
  216.             for(ap = Arp_tab[i];ap != NULLARP;ap = ap->next)
  217.                 if(memcmp(ap->hw_addr,arp.thwaddr,(size_t)at->hwalen) == 0)
  218.                     goto found;
  219.     found:  if(ap != NULLARP && ap->pub){
  220.             memcpy(arp.shwaddr,iface->hwaddr,(size_t)at->hwalen);
  221.             arp.tprotaddr = ap->ip_addr;
  222.             arp.sprotaddr = iface->addr;
  223.             arp.opcode = REVARP_REPLY;
  224.             if((bp = htonarp(&arp)) == NULLBUF)
  225.                 return;
  226.             if(iface->forw != NULLIF)
  227.                 (*iface->forw->output)(iface->forw,
  228.                  arp.thwaddr,iface->forw->hwaddr,REVARP_TYPE,bp);
  229.             else 
  230.                 (*iface->output)(iface,arp.thwaddr,
  231.                  iface->hwaddr,REVARP_TYPE,bp);
  232.             Arp_stat.inreq++;
  233.         }
  234.     }
  235. }
  236. /* Add an IP-addr / hardware-addr pair to the ARP table */
  237. struct arp_tab *
  238. arp_add(ipaddr,hardware,hw_addr,pub,iface)
  239. int32 ipaddr;           /* IP address, host order */
  240. int16 hardware;         /* Hardware type */
  241. char *hw_addr;          /* Hardware address, if known; NULLCHAR otherwise */
  242. int pub;                /* Publish this entry? */
  243. struct iface *iface;
  244. {
  245.     struct mbuf *bp;
  246.     register struct arp_tab *ap;
  247.     struct arp_type *at;
  248.     unsigned hashval;
  249.  
  250.     if(hardware >=NHWTYPES)
  251.         return NULLARP; /* Invalid hardware type */
  252.     at = &Arp_type[hardware];
  253.  
  254.     if((ap = arp_lookup(hardware,ipaddr,iface)) == NULLARP){
  255.         /* New entry */
  256.         ap = (struct arp_tab *)callocw(1,sizeof(struct arp_tab));
  257.         ap->hw_addr = mallocw((unsigned)at->hwalen);
  258.     ap->timer.func = arp_timeout;
  259.         ap->timer.arg = ap;
  260.         ap->hardware = hardware;
  261.         ap->ip_addr = ipaddr;
  262.     ap->iface = iface;
  263.  
  264.         /* Put on head of hash chain */
  265.         hashval = hash_ip(ipaddr);
  266.         ap->prev = NULLARP;
  267.         ap->next = Arp_tab[hashval];
  268.         Arp_tab[hashval] = ap;
  269.         if(ap->next != NULLARP){
  270.             ap->next->prev = ap;
  271.         }
  272.     }
  273.     if(hw_addr == NULLCHAR){
  274.         /* Await response */
  275.         ap->state = ARP_PENDING;
  276.         set_timer(&ap->timer,Arp_type[hardware].pendtime * 1000L);
  277.     } else {
  278.         /* Response has come in, update entry and run through queue */
  279.         ap->state = ARP_VALID;
  280.         set_timer(&ap->timer,ARPLIFE*1000L);
  281.         memcpy(ap->hw_addr,hw_addr,(size_t)at->hwalen);
  282.         ap->pub = pub;
  283.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  284.             ip_route(NULLIF,bp,0);
  285.     }
  286.     start_timer(&ap->timer);
  287.     return ap;
  288. }
  289.  
  290. /* Remove an entry from the ARP table */
  291. void
  292. arp_drop(p)
  293. void *p;
  294. {
  295.     register struct arp_tab *ap;
  296.  
  297.     ap = (struct arp_tab *)p;
  298.     if(ap == NULLARP)
  299.         return;
  300.     stop_timer(&ap->timer); /* Shouldn't be necessary */
  301.     if(ap->next != NULLARP)
  302.         ap->next->prev = ap->prev;
  303.     if(ap->prev != NULLARP)
  304.         ap->prev->next = ap->next;
  305.     else
  306.         Arp_tab[hash_ip(ap->ip_addr)] = ap->next;
  307.     free_q(&ap->pending);
  308.     free(ap->hw_addr);
  309.     free((char *)ap);
  310. }
  311.  
  312. /* Look up the given IP address in the ARP table */
  313. struct arp_tab *
  314. arp_lookup(hardware,ipaddr,iface)
  315. int16 hardware;
  316. int32 ipaddr;
  317. struct iface *iface;
  318. {
  319.     register struct arp_tab *ap;
  320.  
  321.     for(ap = Arp_tab[hash_ip(ipaddr)]; ap != NULLARP; ap = ap->next){
  322.     if(ap->ip_addr == ipaddr && ap->hardware == hardware \
  323.         && ap->iface == iface)
  324.             break;
  325.     }
  326.     return ap;
  327. }
  328. /* Send an ARP request to resolve IP address target_ip */
  329. static void
  330. arp_output(iface,hardware,target,hw_addr)
  331. struct iface *iface;
  332. int16 hardware;
  333. int32 target;
  334. char *hw_addr;
  335. {
  336.     struct arp arp;
  337.     struct mbuf *bp;
  338.     struct arp_type *at;
  339.  
  340.     at = &Arp_type[hardware];
  341.     if(iface->output == NULLFP((struct iface*,char*,char*,int16,struct mbuf*)))
  342.         return;
  343.     
  344.     arp.hardware = hardware;
  345.     arp.protocol = at->iptype;
  346.     arp.hwalen = at->hwalen;
  347.     arp.pralen = sizeof(int32);
  348.     arp.opcode = ARP_REQUEST;
  349.     memcpy(arp.shwaddr,iface->hwaddr,(size_t)at->hwalen);
  350.     arp.sprotaddr = iface->addr;
  351.     memset(arp.thwaddr,0,(size_t)at->hwalen);
  352.     arp.tprotaddr = target;
  353.     if((bp = htonarp(&arp)) == NULLBUF)
  354.         return;
  355.     if(hw_addr == NULLCHAR)
  356.         (*iface->output)(iface,at->bdcst,iface->hwaddr,at->arptype,bp);
  357.     else
  358.     (*iface->output)(iface,hw_addr,iface->hwaddr,at->arptype,bp);
  359.     Arp_stat.outreq++;
  360. }
  361.  
  362. /* Called when an ARP entry times out. If an entry has been a valid
  363.  * one we will send out an ARP reply. If this one does not succed,
  364.  * the ARP entry will be dropped. -- sm6rpz
  365.  *
  366.  * Made configurable by WG7J.
  367.  */
  368. static void
  369. arp_timeout(p)
  370. void *p;
  371. {
  372.     struct arp_type *at;
  373.     char *hwaddr;
  374.     struct arp_tab *ap = (struct arp_tab *)p;
  375.     
  376.     if(ap == NULLARP)
  377.     return;
  378.     stop_timer(&ap->timer);
  379.     /* Check to see if the timer is set to ARPLIFE or pendtime. Set_timer()
  380.      * adds at least one tick so we must do a little more flexible check.
  381.      */
  382.     if( (ap->iface->flags & ARP_KEEPALIVE) &&
  383.     (dur_timer(&ap->timer) >= ARPLIFE * 1000L)) {
  384.     at = &Arp_type[ap->hardware];
  385.     set_timer(&ap->timer,at->pendtime * 1000L);
  386.     /* timer functions should NEVER call blocked allocs ! - WG7J */
  387.     if((hwaddr = (char *)mallocw((unsigned)at->hwalen))!=NULLCHAR) {
  388.         memcpy(hwaddr,ap->hw_addr,(size_t)at->hwalen);
  389.         arp_output(ap->iface,ap->hardware,ap->ip_addr,hwaddr);
  390.         free(hwaddr);           /* clean up */
  391.     }
  392.     start_timer(&ap->timer);
  393.     } else
  394.     arp_drop(ap);
  395. }
  396.  
  397.